﻿using Infrastructure.Config;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using OtherLib.TenXun.Pay;
using OtherLib.TenXun.Pay.Dto;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace OtherLib.TenXun
{
    public class TenXunPayUtil
    {
        #region 配置
        WxConfig config;
        WxPayApi wxPayApi;
        static TenXunPayUtil()
        {
            if (map == null)
            {
                map = new System.Collections.Concurrent.ConcurrentDictionary<string, TenXunPayUtil>();
                var tenXunPaysSection = ApplicationConfig.GetConfig().GetSection("TenXunPays");

                foreach (var item in tenXunPaysSection.GetChildren())
                {
                    WxConfig config = new WxConfig();
                    item.Bind(config);

                    config.IP = "8.8.8.8";
                    TenXunPayUtil.map.TryAdd(config.Name, new TenXunPayUtil() { config = config, wxPayApi = new WxPayApi(config) });
                }
            }
        }
        static System.Collections.Concurrent.ConcurrentDictionary<string, TenXunPayUtil> map = null;

        public static TenXunPayUtil GetUtilByName(string name)
        {
            map.TryGetValue(name, out TenXunPayUtil wxPayService);
            return wxPayService;
        }
        #endregion

        #region 接口
        public async Task<Tuple<bool, string>> AppPay(string body, string outTradeNo, int totalFee)
        {
            try
            {
                var data = new WxPayData();
                data.SetValue("body", body);//商品描述
                                            //data.SetValue("attach", outTradeIds);//附加数据
                data.SetValue("out_trade_no", outTradeNo);//随机字符串
                data.SetValue("total_fee", totalFee);//总金额
                data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
                data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
                                                                                                     //data.SetValue("goods_tag", "jjj");//商品标记
                data.SetValue("trade_type", "APP");//交易类型
                var result = await wxPayApi.UnifiedOrder(data);//调用统一下单接口


                return result == null
                    ? new Tuple<bool, string>(false, "返回数据为空！")
                    : new Tuple<bool, string>(true, AppSign(result.ToJson()));
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        public async Task<Tuple<bool, string>> MwebPay(string body, string outTradeNo, int totalFee, string ip)
        {
            try
            {
                var data = new WxPayData();
                data.SetValue("body", body);//商品描述
                                            //data.SetValue("attach", outTradeIds);//附加数据
                data.SetValue("out_trade_no", outTradeNo);//随机字符串
                data.SetValue("total_fee", totalFee);//总金额
                data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
                data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
                                                                                                     //data.SetValue("goods_tag", "jjj");//商品标记
                data.SetValue("trade_type", "MWEB");//交易类型
                data.SetValue("spbill_create_ip", ip);//终端ip	 

                var result = await wxPayApi.UnifiedOrder(data);//调用统一下单接口

                return data == null
                    ? new Tuple<bool, string>(false, "返回数据为空！")
                    : new Tuple<bool, string>(true, data.GetValue("mweb_url").ToString());
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }



        public async Task<Tuple<bool, string>> JsApiPay(string body, string outTradeNo, int totalFee, string openId)
        {
            try
            {
                var data = await wxPayApi.GetUnifiedOrderResult(body, outTradeNo, totalFee, openId);

                var wxJsApiParam = wxPayApi.GetJsApiParameters(data);//获取H5调起JS API参数    
                return wxJsApiParam == null
                    ? new Tuple<bool, string>(false, "返回数据为空！")
                    : new Tuple<bool, string>(true, wxJsApiParam);
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }





        public async Task<WeChatRefundResponse> WeChatRefund(string transactionId, string outTradeNo, int totalFee, int refundFee, string outRefundNo)
        {
            try
            {
                var result = await wxPayApi.RefundRun(transactionId, outTradeNo, totalFee, refundFee, outRefundNo);
                var response = JsonConvert.DeserializeObject<WeChatRefundResponse>(result);
                return response;
            }
            catch (Exception e)
            {
                return new WeChatRefundResponse { result_code = "Fail", return_msg = e.Message };
            }
        }

        public async Task<WeChatRefundQueryResponse> WeChatRefundQuery(string refundId, string outRefundNo, string transactionId, string outTradeNo)
        {
            try
            {
                var result = await wxPayApi.QueryRefundRun(refundId, outRefundNo, transactionId, outTradeNo);
                var response = JsonConvert.DeserializeObject<WeChatRefundQueryResponse>(result);
                return response;
            }
            catch (Exception e)
            {
                return new WeChatRefundQueryResponse { result_code = "Fail", return_msg = e.Message };
            }
        }

        public async Task<WeChatNotifyRequest> WeChatNotify(Stream weChatReturnData)
        {
            //接收从微信后台POST过来的数据
            var s = weChatReturnData;
            int count;
            var buffer = new byte[1024];
            var builder = new StringBuilder();
            while ((count = s.Read(buffer, 0, 1024)) > 0)
            {
                builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            }
            s.Flush();
            s.Dispose();
            Console.WriteLine(builder);
            var notifyData = new WxPayData();
            try
            {
                notifyData.FromXml(builder.ToString(), config.Key);
            }
            catch (Exception e)
            {
                var res = new WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", e.Message);
                return new WeChatNotifyRequest { IsVerify = false, PayNo = "", TradeIds = "", PayTime = "", Sign = "", Content = res };
            }

            //检查支付结果中transaction_id是否存在
            if (!notifyData.IsSet("transaction_id"))
            {
                //若transaction_id不存在，则立即返回结果给微信支付后台
                var res = new WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", "支付结果中微信订单号不存在");
                return new WeChatNotifyRequest { IsVerify = false, PayNo = "", TradeIds = "", PayTime = "", Sign = "", Content = res };
            }

            var transactionId = notifyData.GetValue("transaction_id").ToString();
            var tradeIds = notifyData.GetValue("out_trade_no").ToString();
            var payTime = notifyData.GetValue("time_end").ToString();
            var payMoney = Convert.ToInt32(notifyData.GetValue("total_fee").ToString());

            //查询订单，判断订单真实性
            if (!await QueryOrder(transactionId))
            {
                //若订单查询失败，则立即返回结果给微信支付后台
                var res = new WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", "订单查询失败");
                return new WeChatNotifyRequest { IsVerify = false, PayNo = "", TradeIds = "", PayTime = "", Sign = "", Content = res };
            }
            //查询订单成功
            else
            {
                var res = new WxPayData();
                res.SetValue("return_code", "SUCCESS");
                res.SetValue("return_msg", "OK");
                return new WeChatNotifyRequest { IsVerify = true, PayNo = transactionId, TradeIds = tradeIds, PayMoney = payMoney, PayTime = payTime, Sign = "", Content = res };
            }
        }
        //查询订单
        private async Task<bool> QueryOrder(string transactionId)
        {
            var req = new WxPayData();
            req.SetValue("transaction_id", transactionId);
            var res = await wxPayApi.OrderQuery(req);
            return res.GetValue("return_code").ToString() == "SUCCESS" && res.GetValue("result_code").ToString() == "SUCCESS";
        }

        public string AppSign(string preJson)
        {
            var dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(preJson);
            var data = new WxPayData();
            data.SetValue("appid", dic["appid"]);
            data.SetValue("partnerid", dic["mch_id"]);
            data.SetValue("prepayid", dic["prepay_id"]);
            data.SetValue("package", "Sign=WXPay");
            data.SetValue("noncestr", WxPayApi.GenerateNonceStr());
            data.SetValue("timestamp", WxPayApi.GenerateTimeStamp());
            data.SetValue("sign", data.MakeSign(config.Key));
            return data.ToJson();
        }
        #endregion
    }
}
